#include <sobjc-commons/defines.h>
#include <sobjc-commons/str_list.h>
#include "patch.h"
#include "command.h"
#include "name.h"

typedef struct objc_patch objc_patch, *objc_patch_t;

struct objc_patch {
  size_t lc;
  size_t len;
  char *s;
};

OBJC_SIMPLE_DEF_LIST(patch_list, objc_patch_t)

static objc_patch_list_t sort_patches(objc_patch_list_t);

static objc_patch_list_t all_patches = NULL;
static unsigned long npatches = 0;

void
objc_add_patch(size_t lc, size_t len, const char *s)
{
  objc_patch_t patch;

  patch = ALLOC(objc_patch);
  patch->lc = lc;
  patch->len = len;
  if (s != NULL)
    patch->s = objc_strdup(s);
  else
    patch->s = NULL;

  objc_patch_list_add_set(&all_patches, patch);
  npatches++;
}

void
objc_apply_patches(const char *src, size_t src_len, FILE *f)
{
  objc_patch_t p;
  objc_patch_list_t ps;
  size_t len, lc = 0;

  if (npatches > 1)
    all_patches = sort_patches(all_patches);
 
  ps = all_patches;
  while (ps) {
    p = ps->car;
    len = p->lc - lc;
    fwrite(src, len, 1, f);
    src += len;
    lc += len;

    if (p->s != NULL)
      fwrite(p->s, strlen(p->s), 1, f);
    src += p->len;
    lc += p->len;

    ps = ps->cdr;
  }
  len = src_len - lc;
  if (len > 0)
    fwrite(src, len, 1, f);

  all_patches = NULL;
  npatches = 0;
}

objc_patch_list_t
sort_patches(objc_patch_list_t patches)
{
  objc_patch_t pivot;
  objc_patch_list_t head = NULL, tail = NULL;

  if (patches != NULL) {
    pivot = patches->car;
    patches = patches->cdr;
    while (patches) {
      if (pivot->lc > patches->car->lc)
        head = objc_patch_list_add(head, patches->car);
      else
        tail = objc_patch_list_add(tail, patches->car);
      patches = patches->cdr;
    }
    return objc_patch_list_concate(sort_patches(head), objc_make_patch_list(pivot, sort_patches(tail)));
  } else
    return NULL;
}

